import { cloneDeep } from "lodash";
import dayjs from "dayjs";

import { yunNao } from "@src/api/yunNao";
import { dataCategory, getDefaultDataBaseData, sendParamsStructure } from "@src/dataFormatConversion/constant"
import { createSerialDates } from "@src/dataFormatConversion/tool";

import { DomMessageInstance } from "../../utils/DomMessage";
import { DataSourceTypeByDateEnum, DataSourceTypeEnum } from "@src/globalData/enum";
import { sendParamFilterData } from "@src/dataFormatConversion/formatData";
import { getWeekDates } from "../../utils/common";
import { getTimePoints } from "@src/utils/common";

/**
 * 判断每个类型的数量是否达到
 * 调用云脑接口存储数据  通过云脑接口调用数据组数据，最终将数据存储到数组组数据库
 */
const saveWebSpiderData = async (type: string, sendParam: { [key: string]: any }) => {
  /**没有爬取时间的不往下执行 */
  if (!sendParam[type].data[0].business_time) return;

  try {
    const saveData = JSON.parse(JSON.stringify(sendParam[type]))

    /**置空已调用存储接口的类型数据，重新开始爬取存储 */
    console.log('存储原数据：', JSON.parse(JSON.stringify(sendParam[type].data)))
    sendParam[type].data = getDefaultDataBaseData()

    const {haveData, saveDataFilter} = sendParamFilterData(saveData.data[0].data)
    if(!haveData) {
      DomMessageInstance.error({content:'无数据，不存'})
      console.log('无数据，不存')
      return Promise.reject()
    }
    saveData.data[0].data = saveDataFilter

    console.log('存储数据：', saveData)
    await yunNao.datapreservation([saveData]);
    console.log("获取数据存储成功", dayjs().format("YYYY-MM-DD HH:mm:ss"));
  } catch (e) {
    DomMessageInstance.error({content:'获取数据存储失败, 请联系开发人员'})
    console.error("获取数据存储失败: ", e);
    return Promise.reject(e)
  }
}

export const saveWebSpiderDataV2 = async (saveData:{
  data_item: string;
  data: any[];
  date_time: string;
}) => {
  try {
    const haveData = (saveData?.data || []).some(item =>{
      const objVal = cloneDeep(item)
      delete objVal.sourceIdentity
      delete objVal.runDate
      delete objVal.oriRunDate

      return Object.values(objVal).some(val =>{
        if(typeof val === 'number') return true
        return !!val
      })
    })

    if(!haveData) {
      DomMessageInstance.error({content:'无数据，不存'})
      console.log('无数据，不存')
      return Promise.reject()
    }

    console.log('存储数据：', saveData)
    await yunNao.datapreservationV2(saveData);
    console.log("获取数据存储成功", dayjs().format("YYYY-MM-DD HH:mm:ss"));
  } catch (e) {
    DomMessageInstance.error({content:'获取数据存储失败, 请联系开发人员'})
    console.error("获取数据存储失败: ", e);
    return Promise.reject(e)
  }
}

/** 调用云脑接口存储的数据结构 */
export const yunNaoSaveInformationDisclosureData = async (formatData: any) => {
  const sendParam: { [key: string]: any } = cloneDeep(sendParamsStructure);
  const typeKey = formatData.dataType
  const saveData = formatData.dataSource
  if(!typeKey || !saveData?.length || !formatData?.date) {
    const tip = '数据获取不完整，保存失败'
    DomMessageInstance.error({content:tip})
    return Promise.reject(new Error(tip))
  }
  try {
    if (dataCategory[DataSourceTypeByDateEnum.D_REDUCE_DATE].includes(typeKey)) {
      Object.assign(
        sendParam[DataSourceTypeByDateEnum.D_REDUCE_DATE].data[0].data,
        { [typeKey]: saveData }
      );
      sendParam[DataSourceTypeByDateEnum.D_REDUCE_DATE].data[0].business_time = formatData.date;
      await saveWebSpiderData(DataSourceTypeByDateEnum.D_REDUCE_DATE, sendParam)
    } else if (dataCategory[DataSourceTypeByDateEnum.D_DATE].includes(typeKey)) {
      Object.assign(
        sendParam[DataSourceTypeByDateEnum.D_DATE].data[0].data,
        { [typeKey]: saveData }
      );
      sendParam[DataSourceTypeByDateEnum.D_DATE].data[0].business_time = formatData.date;
      await saveWebSpiderData(DataSourceTypeByDateEnum.D_DATE, sendParam)
    } else if (dataCategory.d_add_date.includes(typeKey)) {
      Object.assign(
        sendParam[DataSourceTypeByDateEnum.D_ADD_DATE].data[0].data,
        { [typeKey]: saveData }
      );
      sendParam[DataSourceTypeByDateEnum.D_ADD_DATE].data[0].business_time = formatData.date;
      await saveWebSpiderData(DataSourceTypeByDateEnum.D_ADD_DATE, sendParam)
    }
  } catch(e) {
    return Promise.reject(e)
  }
};

type DataInfo = {
  statement: string, // 说明
  pageName: string, // 数据项名称
  typeKey: DataSourceTypeEnum | string, // 表名，后端加密
  cols: number[], // 获取的列数据索引值集合
  startRow?: number, 
  keys: string[], // 对应列的索引值
  pageValidate?: Function, // 获取数据前的校验方法
  data?: string[][], // 获取到dom节点中的表格的二维数组数据
  dataType?: 'week', // 默认无值；区分周或其它
  tableDomType?: number // 不同表格的dom不同，需要区分获取数据的方式
}

/**
 * 校验是否全选数据项
  【信息披露】-【综合查询】-【供需与约束】-【预测信息】联络线受电负荷：【联络线输电能力预测】-【日前】`,
   日前系统间联络线输电曲线预测'
 */
const receivingLoadValidate = () => {
  const dom = document?.querySelector('iframe')?.contentDocument || document
  return {
    validateResult: dom.querySelector('.fr-checkbox-checkon')?.innerHTML === '全选/不选', 
    errMsg: '必须全选数据项才能获取 日前系统间联络线输电曲线预测 数据'
  }
}

/**
 * 校验是否选 直调负荷
  【【信息披露】-【综合查询】-【供需与约束】-【预测信息】-【系统负荷预测】-【次周】
  周前系统负荷预测
 */
const systemLoadValidate = () => {
  const dom = document?.querySelector('iframe')?.contentDocument || document
  const theDom = dom.querySelectorAll('.fr-trigger-texteditor')?.[2] as any
  return {
    validateResult: theDom?.value === '直调负荷', 
    errMsg: '请选直调负荷 周前系统负荷预测 数据'
  }
}

/** 综合查询系统中需要手动获取的数据项 */
const getDataInfo:DataInfo[] = [
     /**
   *5、【信息披露】-【综合查询】-【供需与约束】-【出力预测】-【日前】-【抽蓄计划发电】
   * 抽蓄数据（预测-出清前）
   * D+1日
   * AHEAD_PUMPED_BEFORE_INFO = "ahead_pumped_before_info"
   '抽蓄总出力预测'
   */

    /**
    *6、【信息披露】-【综合查询】-【供需与约束】-【预测信息】直调负荷：【系统负荷预测】-【日前】联络线受电负荷：【联络线输电能力预测】-【日前】风光出力：【出力预测】-【日前】-【分电源类型的新能源】
    * 市场披露信息（预测-出清后）（包括：直调负荷、联络线受电负荷、风电总出力预测、光伏总出力预测、总出力预测）
    * D+1日
    * AHEAD_MARKET_AFTER_INFO = "ahead_market_after_info"
    *    直调负荷： '日前系统负荷预测'
    *    "ahead_market_after_info:[
    *     {
    *       "runDate": "2024-04-21 00:00",
    *       "systemLoad": 54796.121
    *     },....]
    * 
    *     联络线：'日前系统间联络线输电曲线预测'
    *     "ahead_market_after_info:[
    *     {
    *       "runDate": "2024-04-21 00:00",
    *       "receivingLoad": 11997.819
    *     },....]
    * 
    *     风力：'分电源类型的新能源总出力预测'   nth-child(2 3)
    *     "ahead_market_after_info:[
    *       {
    *         "runDate": "2024-04-21 00:00",
    *         "windPowerTotal": 3424.56
    *         pvTotal: 333
    *       },....]
    */
  {
    statement: `【信息披露】-【综合查询】-【供需与约束】-【出力预测】-【日前】-【抽蓄计划发电】抽蓄数据（预测-出清前）`,
    pageName: '抽蓄总出力预测',
    cols: [2], // 获取表格中第？列的数据
    typeKey: DataSourceTypeEnum.AHEAD_PUMPED_BEFORE_INFO,
    keys: ['pumpingTotal'] // 列数据对应的入库的字段
  },
  {
    statement: `【信息披露】-【综合查询】-【供需与约束】-【预测信息】直调负荷：【系统负荷预测】`,
    pageName: '日前系统负荷预测',
    cols: [2],
    typeKey: DataSourceTypeEnum.AHEAD_MARKET_AFTER_INFO,
    keys: ['systemLoad']
  },
  {
    statement: `【信息披露】-【综合查询】-【供需与约束】-【预测信息】联络线受电负荷：【联络线输电能力预测】-【日前】`,
    pageName: '日前系统间联络线输电曲线预测',
    cols: [2],
    typeKey: DataSourceTypeEnum.AHEAD_MARKET_AFTER_INFO,
    keys: ['receivingLoad'],
    pageValidate: receivingLoadValidate
  },
  {
    statement: `【信息披露】-【综合查询】-【供需与约束】-【预测信息】直调负荷：【系统负荷预测】风光出力：【出力预测】-【日前】-【分电源类型的新能源】`,
    pageName: '分电源类型的新能源总出力预测',
    cols: [2,3],
    typeKey: DataSourceTypeEnum.AHEAD_MARKET_AFTER_INFO,
    keys: ['windPowerTotal','pvTotal']
  },

  /*************************  周数据  ***********************************************/
  {
    statement: `【信息披露】-【综合查询】-【供需与约束】-【出力预测】-【周前】-【抽蓄】`,
    pageName: '周前抽蓄总出力预测',
    cols: [2,3,4,5,6,7,8],
    // typeKey: 'trading_sd_etrm_spider_week_pumpedTotal',
    typeKey: 's5md4B4UMTwssISaockSaxqQqKnQStKG0R+hzHfu5l0cpS4qqdNuMXvznSiveoQ1',
    dataType: 'week',
    keys: ['pumpingTotal']
  },
  {
    statement: `【信息披露】-【综合查询】-【供需与约束】-【出力预测】-【周前】-【新能源】`,
    pageName: '周前新能源总出力预测',
    cols: [2,3,4,5,6,7,8],
    // typeKey: 'trading_sd_etrm_spider_week_newEnergyTotal',
    typeKey: 's5md4B4UMTwssISaockSa/iFKG0uL/FlnjMopr3kIFu9HWIWJ7NPNZIkNX0Sv6/D',
    dataType: 'week',
    keys: ['newEnergyTotal']
  },
  {
    statement: `【信息披露】-【综合查询】-【供需与约束】-【预测信息】-【省间联络线输电曲线预测】-【次周】`,
    pageName: '次周联络线输电能力预测',
    cols: [2,3,4,5,6,7,8],
    // typeKey: 'trading_sd_etrm_spider_week_receivingLoad',
    typeKey: 's5md4B4UMTwssISaockSa2FeORE8EAEO3Qr8b62hSUFC8oclI1BnqjETY/o9nDRq',
    dataType: 'week',
    keys: ['receivingLoad'],
    pageValidate: receivingLoadValidate
  },
  {
    statement: `【信息披露】-【综合查询】-【供需与约束】-【预测信息】-【系统负荷预测】-【次周】`,
    pageName: '周前系统负荷预测',
    cols: [2,3,4,5,6,7,8],
    // typeKey: 'trading_sd_etrm_spider_week_systemLoad',
    typeKey: 's5md4B4UMTwssISaockSa/IMYCmlNz5/+IUIT8skj38Eo7XXpP8kwoW1k3DS4riu',
    dataType: 'week',
    pageValidate: systemLoadValidate,
    keys: ['systemLoad'],
    tableDomType: 1
  }
]

/** 获取dom节点中的数据 */
const getDomTableData = (dataInfo:Partial<DataInfo>) => {
  const {cols = [], tableDomType} = dataInfo
  let data:string[][] = []
  let colData:any[] = []

  const dom = document?.querySelector('iframe')?.contentDocument || document


  for(let i = 0; i < cols.length; i++) {
    if(tableDomType === 1) {
      const list = Array.from(dom?.querySelector('.rows-height-counter')?.querySelectorAll?.(`tr > td:nth-child(${cols[i]})`) || {length:0});
      colData = list.slice(list.length-96).map(val => val.innerHTML)
    } else {
      colData = Array.from(dom?.querySelector('#frozen-center')?.querySelectorAll?.(`tr > td:nth-child(${cols[i]}) > div`) || {length:0}).map(val => val.innerHTML)
    }

    data.push(colData)
  }

  return data
}

/** 点击页面中 获取数据 按钮时触发的获取dom中数据的方法 */
export const getCurrentPageInfo = ():Partial<DataInfo> | void | undefined => {
  const dom = document?.querySelector('iframe')?.contentDocument || document
  const _pageName = (dom || document).querySelector('tspan')?.innerHTML
  if(!_pageName) return DomMessageInstance.error({content:'获取页面信息失败'})
 
  const dataInfo = getDataInfo.find(item => item.pageName === _pageName)
  if(!dataInfo) return DomMessageInstance.error({content:'当前页面未配置获取数据 <br> 或放大窗口再试'})
  if(dataInfo?.pageValidate) {
    const {validateResult = false, errMsg = ''} = dataInfo.pageValidate()
    if(!validateResult) return DomMessageInstance.error({content: errMsg})
  }

  const {statement, pageName} = dataInfo

  const data = getDomTableData(dataInfo)

  if(!data?.[0].length) {
    const message = `获取数据失败! <br> ${statement} <br> ${pageName}`
    return DomMessageInstance.error({content:message})
  }

  return {
    ...dataInfo,
    data
  }
}

/** 周数据的统一结构 */
const combineSaveStructure = (data:any[], dataItem:string) => {
  return {
    data_item: dataItem,
    data,
    date_time: dayjs().format('YYYY-MM-DD HH:mm:ss')
  }
}

/** 处理周数据 */
const dealWeekdata = (dataInfo:Partial<DataInfo>, pdate:string) => {
  const sourceIdentity = import.meta.env.VITE_APP_SOURCE_ID
  const {data, typeKey, keys} = dataInfo

  const oriTimeArr96 = getTimePoints(96)
  const runTime96 = getTimePoints('96_2')
  const weekDates = getWeekDates(pdate) as string[]

  const dealedData:any[] = [];

  (data || [])?.forEach((item, idx) => {
     oriTimeArr96.forEach((time, index) => dealedData.push({
      sourceIdentity,
      // "runDate": "2024-09-26 00:00",
      // "oriRunDate": "2024-09-26 00:15",
      runDate:`${weekDates[idx]} ${runTime96[index]}`,
      oriRunDate:`${weekDates[idx]} ${time}`,
      [keys?.[0] as string]: item[index]
    }))
  })

  return combineSaveStructure(dealedData, typeKey as string)
}

/** 处理从dom中获取到的数据 */
const dealData = (dataInfo:Partial<DataInfo>, pdate:string) => {
  if(Number(dataInfo?.data?.[0]?.length) < 2) return DomMessageInstance.error({content:'页面数据不完整'})

  if(!pdate) DomMessageInstance.error({content:'获取日期失败'})
  // 获取 96 点数据
  const timeArr96 = createSerialDates([pdate, pdate],96,'HH:mm')

  const {cols = [], data = [], keys = [], typeKey = ''} = dataInfo

  const dataSource = timeArr96.map((time, index) => {
    const saveData:Record<string, any> = {
      runDate:`${pdate} ${time}`
    }

    for(let i = 0; i < cols.length; i++) {
      saveData[keys[i]] = data[i][index]
    }

    return saveData
  })

  return {
   dataSource,
   dataType: typeKey,
   date: pdate
  }
}

/** 处理周数据和非周数据 */
export const dealAllTypeData = (dataInfo:Partial<DataInfo>) => {
  const pdateDom = Array.from((document?.querySelector('iframe')?.contentDocument || document)?.querySelectorAll(".fr-trigger-editor"))?.find(val => val.getAttribute('widgetname') === '日期')?.querySelector('.fr-trigger-texteditor') as any
  const pdate:string = pdateDom?.value || ''

  const {dataType} = dataInfo
  if(dataType === 'week') return dealWeekdata(dataInfo, pdate)
  return dealData(dataInfo, pdate)
}